<?php

namespace Dongasai\WkProtoPhp\Packets;

use Dongasai\WkProtoPhp\Enums\FrameType;
use Dongasai\WkProtoPhp\Protocol;
use Dongasai\WkProtoPhp\Framer;
use Dongasai\WkProtoPhp\Encoder;
use Dongasai\WkProtoPhp\Decoder;
use Dongasai\WkProtoPhp\Enums\DeviceFlag;
use Dongasai\WkProtoPhp\JsonSerializableInterface;
use Dongasai\WkProtoPhp\JsonSerializableTrait;

/**
 * CONNECT连接包
 */
class ConnectPacket extends Framer implements JsonSerializableInterface
{
    use JsonSerializableTrait;
    
    private int $version = Protocol::LATEST_VERSION;
    private string $clientKey = '';
    private string $deviceId = '';
    private int $deviceFlag = DeviceFlag::ANDROID->value;
    private int $clientTimestamp = 0;
    private string $uid = '';
    private string $token = '';

    public function __construct()
    {
        parent::__construct(FrameType::CONNECT->value);
    }

    public function getFrameType(): int
    {
        return FrameType::CONNECT->value;
    }

    public function __toString(): string
    {
        return sprintf(
            'CONNECT UID:%s DeviceFlag:%d DeviceId:%s ClientTimestamp:%d Token:%s Version:%d',
            $this->uid,
            $this->deviceFlag,
            $this->deviceId,
            $this->clientTimestamp,
            $this->token,
            $this->version
        );
    }

    // Getters and Setters
    public function getVersion(): int
    {
        return $this->version;
    }

    public function setVersion(int $version): void
    {
        $this->version = $version;
    }

    public function getClientKey(): string
    {
        return $this->clientKey;
    }

    public function setClientKey(string $clientKey): void
    {
        $this->clientKey = $clientKey;
    }

    public function getDeviceId(): string
    {
        return $this->deviceId;
    }

    public function setDeviceId(string $deviceId): void
    {
        $this->deviceId = $deviceId;
    }

    public function getDeviceFlag(): int
    {
        return $this->deviceFlag;
    }

    /**
     * 获取设备标志枚举
     */
    public function getDeviceFlagEnum(): DeviceFlag
    {
        return DeviceFlag::from($this->deviceFlag);
    }

    public function setDeviceFlag(int $deviceFlag): void
    {
        $this->deviceFlag = $deviceFlag;
    }

    /**
     * 设置设备标志枚举
     */
    public function setDeviceFlagEnum(DeviceFlag $deviceFlag): void
    {
        $this->deviceFlag = $deviceFlag->value;
    }

    public function getClientTimestamp(): int
    {
        return $this->clientTimestamp;
    }

    public function setClientTimestamp(int $clientTimestamp): void
    {
        $this->clientTimestamp = $clientTimestamp;
    }

    public function getUid(): string
    {
        return $this->uid;
    }

    public function setUid(string $uid): void
    {
        $this->uid = $uid;
    }

    public function getToken(): string
    {
        return $this->token;
    }

    public function setToken(string $token): void
    {
        $this->token = $token;
    }

    /**
     * 解码CONNECT包
     */
    public static function decode(Framer $framer, string $data, int $version): self
    {
        $decoder = new Decoder($data);
        $packet = new self();
        
        // 复制framer属性
        $packet->setRemainingLength($framer->getRemainingLength());
        $packet->setNoPersist($framer->getNoPersist());
        $packet->setRedDot($framer->getRedDot());
        $packet->setSyncOnce($framer->getSyncOnce());
        $packet->setDUP($framer->getDUP());
        $packet->setFrameSize($framer->getFrameSize());

        try {
            $packet->version = $decoder->uint8();
            $packet->deviceFlag = $decoder->uint8();
            $packet->deviceId = $decoder->string();
            $packet->uid = $decoder->string();
            $packet->token = $decoder->string();
            $packet->clientTimestamp = $decoder->int64();
            $packet->clientKey = $decoder->string();
        } catch (\Exception $e) {
            throw new \RuntimeException('解码CONNECT包失败: ' . $e->getMessage(), 0, $e);
        }

        return $packet;
    }

    /**
     * 编码CONNECT包
     */
    public function encode(Encoder $encoder, int $version): void
    {
        $encoder->writeUint8($this->version);
        $encoder->writeUint8($this->deviceFlag);
        $encoder->writeString($this->deviceId);
        $encoder->writeString($this->uid);
        $encoder->writeString($this->token);
        $encoder->writeInt64($this->clientTimestamp);
        $encoder->writeString($this->clientKey);
    }

    /**
     * 计算CONNECT包大小
     */
    public function size(int $version): int
    {
        $size = 0;
        $size += 1; // VersionByteSize
        $size += 1; // DeviceFlagByteSize
        $size += 2 + strlen($this->deviceId); // StringFixLenByteSize + deviceId length
        $size += 2 + strlen($this->uid); // StringFixLenByteSize + uid length
        $size += 2 + strlen($this->token); // StringFixLenByteSize + token length
        $size += 8; // ClientTimestampByteSize
        $size += 2 + strlen($this->clientKey); // StringFixLenByteSize + clientKey length
        return $size;
    }
}